package com.ruoyi.common.redis.configure;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.Decoder;
import org.redisson.client.protocol.Encoder;
import org.redisson.config.Config;
import org.redisson.spring.data.connection.RedissonConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.Filter;
import com.ruoyi.common.core.constant.Constants;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;

import java.io.IOException;
import java.nio.charset.Charset;

/**
 * Redis配置（整合Redisson，并统一使用Fastjson2序列化）
 *
 * @author ruoyi
 */
@Configuration
@EnableCaching
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisConfig extends CachingConfigurerSupport {

    @Value("${spring.redis.host:localhost}")
    private String host;

    @Value("${spring.redis.port:6379}")
    private int port;

    @Value("${spring.redis.password:}")
    private String password;

    @Value("${spring.redis.database:0}")
    private int database;

    @Value("${spring.redis.timeout:3000}")
    private int timeout;

    /**
     * 配置Redisson客户端，并强制其使用Fastjson2进行编码。
     */
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient() {
        Config config = new Config();

        // 单机模式配置
        config.useSingleServer()
                .setAddress("redis://" + host + ":" + port)
                .setPassword(password.isEmpty() ? null : password)
                .setDatabase(database)
                .setConnectTimeout(timeout)
                .setConnectionPoolSize(64)
                .setConnectionMinimumIdleSize(10);

        // 【核心修改】
        // 实现 Redisson 的 Codec 接口，自定义序列化/反序列化逻辑
        config.setCodec(new Codec() {
            private final Charset charset = Charset.forName("UTF-8");
            private final Filter autoTypeFilter = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);

            // --- 核心序列化/反序列化逻辑 ---
            @Override
            public Decoder<Object> getValueDecoder() {
                return (buf, state) -> {
                    if (buf.readableBytes() == 0) {
                        return null;
                    }
                    try (ByteBufInputStream is = new ByteBufInputStream(buf)) {
                        byte[] bytes = new byte[is.available()];
                        is.read(bytes);
                        return JSON.parseObject(bytes, Object.class, autoTypeFilter);
                    } catch (IOException e) {
                        throw new RuntimeException("Fastjson2 decode error", e);
                    }
                };
            }

            @Override
            public Encoder getValueEncoder() {
                return in -> {
                    if (in == null) {
                        return ByteBufAllocator.DEFAULT.buffer(0);
                    }
                    ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
                    try (ByteBufOutputStream os = new ByteBufOutputStream(out)) {
                        JSON.writeTo(os, in, JSONWriter.Feature.WriteClassName);
                        return os.buffer();
                    } catch (IOException e) {
                        out.release();
                        throw new RuntimeException("Fastjson2 encode error", e);
                    }
                };
            }

            // --- Map 相关的序列化/反序列化，直接复用上面的实现 ---
            @Override
            public Decoder<Object> getMapValueDecoder() {
                return getValueDecoder();
            }

            @Override
            public Encoder getMapValueEncoder() {
                return getValueEncoder();
            }

            @Override
            public Decoder<Object> getMapKeyDecoder() {
                return getValueDecoder();
            }

            @Override
            public Encoder getMapKeyEncoder() {
                return getValueEncoder();
            }

            // --- 其他必要的接口方法 ---
            @Override
            public ClassLoader getClassLoader() {
                return getClass().getClassLoader();
            }
        });

        return Redisson.create(config);
    }

    /**
     * 使用Redisson的连接工厂替换默认工厂
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory(RedissonClient redissonClient) {
        return new RedissonConnectionFactory(redissonClient);
    }

    /**
     * 自定义RedisTemplate（使用方案一的Fastjson2序列化器）
     */
    @Bean
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // 使用你确认过的、能正常工作的Fastjson2序列化器
        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);

        // Key使用String序列化
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);

        // Hash键值序列化
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);

        template.afterPropertiesSet();
        return template;
    }
}